#ifndef __MODEL_H__
#define __MODEL_H__

#include <vector>
#include <wx/gdicmn.h>
#include <TiXML/tinyxml.h>

#include "Point2Df.h"
#include "Boundsi.h"
#include "Skin.h"
#include "Face.h"
#include "Mesh.h"
#include "BoolParse.h"

class Model
{
public:
	std::vector<Mesh>	Meshes;
	std::string			Name;

	Model () { }

	// P: polygon support required? used bounds 'n stuff but, you know...
	wxRect GetTextureFaceBounds(wxPoint p, Skin skin)
	{
		for (std::vector<Mesh>::iterator it = Meshes.begin(); it != Meshes.end(); ++it)
		{
			for (std::vector<Face>::iterator fit = (*it).Faces.begin(); fit != (*it).Faces.end(); ++fit)
			{
				Boundsi bounds (wxPoint(9999, 9999), wxPoint(-9999, -9999));

				for (std::vector<Point2Df>::iterator tit = (*fit).TexCoords.begin(); tit != (*fit).TexCoords.end(); ++tit)
				{
					Point2Df &c = (*tit);
					Point2Df coord (c.X * skin.GetWidth(), c.Y * skin.GetHeight());
					bounds.AddPoint(coord);
				}

				if (bounds.ToRectangle().Contains(p))
					return bounds.ToRectangle();
			}
		}

		return wxRect(-1, -1, -1, -1);
	}

	void Save(std::string fileName)
	{
		/*XmlWriterSettings settings = new XmlWriterSettings();
		settings.ConformanceLevel = ConformanceLevel.Fragment;
		settings.Indent = true;
		settings.NewLineOnAttributes = false;
		settings.IndentChars = "\t";

		using (XmlWriter writer = XmlWriter.Create(fileName, settings))
		{
		writer.WriteStartElement("Model");
		writer.WriteAttributeString("Name", Name);

		foreach (var mesh in Meshes)
		mesh.Write(writer);

		writer.WriteEndElement();
		}*/
	}

	static int ParseBeginMode(const std::string &str)
	{
		if (str == "Quads")
			return GL_QUADS;

		throw std::exception();
	}

	static Model *Load(std::string fileName)
	{
		Model *model = new Model();

		TiXmlDocument document;
		document.LoadFile(fileName);

		model->Name = document.RootElement()->Attribute("Name");

		for (TiXmlNode *meshes = document.RootElement()->FirstChild(); meshes != NULL; meshes = meshes->NextSibling())
		{
			TiXmlElement *meshesElement = meshes->ToElement();
			Mesh mesh (meshesElement->Attribute("Name"));

			if (meshesElement->Attribute("Mode") != NULL)
				mesh.Mode = ParseBeginMode(meshesElement->Attribute("Mode"));
			if (meshesElement->Attribute("Translate") != NULL)
				mesh.Translate = Mesh::StringToVertex3(meshesElement->Attribute("Translate"));
			if (meshesElement->Attribute("Pivot") != NULL)
				mesh.Pivot = Mesh::StringToVertex3(meshesElement->Attribute("Pivot"));
			if (meshesElement->Attribute("IsHelmet") != NULL)
				mesh.Helmet = BoolParse(meshesElement->Attribute("IsHelmet"));
			if (meshesElement->Attribute("FollowCursor") != NULL)
				mesh.FollowCursor = BoolParse(meshesElement->Attribute("FollowCursor"));
			if (meshesElement->Attribute("RotateFactor") != NULL)
				mesh.RotateFactor = atof(meshesElement->Attribute("RotateFactor"));
			if (meshesElement->Attribute("Part") != NULL)
				mesh.Part = ParseVisiblePartFlags(meshesElement->Attribute("Part"));

			for (TiXmlNode *faces = meshesElement->FirstChild(); faces != NULL; faces = faces->NextSibling())
			{
				TiXmlElement *faceNode = faces->ToElement();

				if (!caseInsensitiveStringCompare(faceNode->ValueStr(), "Face"))
					continue;

				Face face;
				int i = 0;

				for (TiXmlNode *sub = faceNode->FirstChild(); sub != NULL; sub = sub->NextSibling())
				{
					if (caseInsensitiveStringCompare(sub->ValueStr(), "Vertices"))
						for (TiXmlNode *vertex = sub->FirstChild(); vertex != NULL; vertex = vertex->NextSibling())
						{
							face.Vertices.push_back(Mesh::StringToVertex3(vertex->ToElement()->GetText()));
							face.Colors.push_back(Colorb(255, 255, 255, 255));
						}

					else if (caseInsensitiveStringCompare(sub->ValueStr(), "TexCoords"))
						for (TiXmlNode *texcoord = sub->FirstChild(); texcoord != NULL; texcoord = texcoord->NextSibling())
							face.TexCoords.push_back(Mesh::StringToVertex2(texcoord->ToElement()->GetText()));

					else if (caseInsensitiveStringCompare(sub->ValueStr(), "Indices"))
						for (TiXmlNode *index = sub->FirstChild(); index != NULL; index = index->NextSibling())
							face.Indices.push_back(atoi(index->ToElement()->GetText()));
				}

				mesh.Faces.push_back(face);
			}

			model->Meshes.push_back(mesh);
		}

		return model;
	}
};

#endif